/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package chatsystem.gui;

import chatsystem.FileTransferStatusCB;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import javax.swing.DefaultListModel;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.text.DefaultCaret;

/**
 * Frontend pour le ChatSystem: expose graphiquement les fonctionnalités du 
 * ChatNI.
 * @author OLIO - POISOT
 */
public class ChatGUI extends javax.swing.JFrame
                     implements ListSelectionListener, WindowListener
{   
   /**
    * Creates new form CSFrame
    */
   public ChatGUI(FromGUI b) {

      this.b = b;
      String data;

      connected = false;
      transfer = false;
      sendFilePath = "";

      this.addWindowListener(this);
      initComponents();

      userList = new DefaultListModel();
      listUser.setModel(userList);
      listUser.addListSelectionListener(this);

      tNickname.addKeyListener(new KeyListener()
      {  //Entrée pour se connecter
         @Override public void keyTyped(KeyEvent e) {
            if (e.getKeyChar() == '\n')
               bConnect.doClick();
         }
         @Override public void keyPressed(KeyEvent e) {}
         @Override public void keyReleased(KeyEvent e) {
            refreshBtns(); // grise le bouton Connect si pseudo vide
         }
      });



      //First initialization - No communication started
      listUser.setEnabled(false);
      //listMess.setEnabled(false);
      tListMess.setEditable(false);
      tListMess.setEnabled(false);
      ((DefaultCaret)tListMess.getCaret()).setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
      tListMess.setLineWrap(true);

      fText.setEditable(false);
      fText.setEnabled(false);
      fText.addKeyListener(new KeyListener()
      {  // "Entrée" envoie le message
         @Override public void keyTyped(KeyEvent e) {
            if (e.getKeyChar() == '\n') {
               String ctn = fText.getText();
               fText.setText(ctn.substring(0, ctn.length()-1));
               bSend.doClick();
            }
         }
         @Override public void keyPressed(KeyEvent e) {}
         @Override public void keyReleased(KeyEvent e) {}
      });

      refreshBtns();
      
      // Focus initial pour le champ pseudo
      tNickname.requestFocus();
      
      // Solution extrême pour éviter que les composants ne se redimensionnent
      // tout seul lorsque leur contenu change.
      this.doLayout();
      this.setLayout(null);
   }

/* ToGUI **********************************************************************/
   
    public void addPeer(String nickname)
    {
        userList.addElement(nickname);
        //msgList.addElement("*user "+nickname+" connected.");
        tListMess.append("*user "+nickname+" connected.\n");
    }
    
    public void showMessage(String peer, String message)
    {
        //msgList.addElement(peer+" : "+message);
        tListMess.append(peer+" : "+message+"\n");
        
        // scroll tout en bas pour voir le dernier message
        try {
           tListMess.setCaretPosition(tListMess.getLineStartOffset(tListMess.getLineCount()-1));
        } catch (Throwable e) {
           e.printStackTrace();
        }
    }
    
   public void fileRecv(String peer, String filename) {
      _fileRecvPopup = new FileRecvDialog(b, peer, filename);
   }
    
   public void removePeer(String nickname)
   {
      // Glitch possible si on retire un user qui n'est pas dans la liste.
      if (userList.contains(nickname)) {
         userList.removeElement(nickname);
         //msgList.addElement("*user "+nickname+" disconnected.");
         tListMess.append("*user "+nickname+" disconnected.\n");
      }
   }
    
    public void showConnected(boolean c)
    {
        listUser.setEnabled(c);
        tListMess.setEnabled(c);
        fText.setEditable(c);
        fText.setEnabled(c);
        lNickname.setEnabled(!c);
        tNickname.setEnabled(!c);
        
        userList.clear();
        tListMess.setText("");
        fText.setText("");
        
        String etat = (c) ? ("Connected as "+tNickname.getText()) : ("Disconnected");
        lEtat.setText(etat);
        
        connected = c;
        refreshBtns();
    }
    
/* Swing Listeners ************************************************************/
    
   /** Depuis la liste des utilisateurs */
   public void valueChanged(ListSelectionEvent e) {
      int s = listUser.getSelectedIndex();
      refreshBtns();
   }

   public void windowClosing(WindowEvent e) 
   {
      // peut être déjà fermée depuis longtemps, mais ça marche quand même.
      if (_fileRecvPopup != null)
         _fileRecvPopup.dispose();
        
      // s'assurer de la fermeture propre des connexions réseau.
      b.onDisconnect();
      this.dispose();
   }

    
    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
   // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
   private void initComponents() {

      lUser = new javax.swing.JLabel();
      lMess = new javax.swing.JLabel();
      jScrollPane1 = new javax.swing.JScrollPane();
      listUser = new javax.swing.JList();
      bSend = new javax.swing.JButton();
      bConnect = new javax.swing.JButton();
      bDisconnect = new javax.swing.JButton();
      jScrollPane3 = new javax.swing.JScrollPane();
      fText = new javax.swing.JTextArea();
      lEtat = new java.awt.Label();
      tNickname = new javax.swing.JTextField();
      lNickname = new javax.swing.JLabel();
      jScrollPane4 = new javax.swing.JScrollPane();
      tListMess = new javax.swing.JTextArea();
      lSendFile = new javax.swing.JLabel();
      bSendFile = new javax.swing.JButton();
      bChooseFile = new javax.swing.JButton();
      tFileName = new javax.swing.JTextField();
      lFileStatus = new javax.swing.JLabel();

      setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
      setTitle("Chat System (Poisot - Olio)");
      setName("frame"); // NOI18N
      setResizable(false);

      lUser.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N
      lUser.setText("Remote users");

      lMess.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N
      lMess.setText("Messages");

      listUser.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
      jScrollPane1.setViewportView(listUser);

      bSend.setText("Send");
      bSend.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent evt) {
            bSendActionPerformed(evt);
         }
      });

      bConnect.setText("Connect");
      bConnect.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent evt) {
            bConnectActionPerformed(evt);
         }
      });

      bDisconnect.setText("Disconnect");
      bDisconnect.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent evt) {
            bDisconnectActionPerformed(evt);
         }
      });

      fText.setColumns(20);
      fText.setLineWrap(true);
      fText.setRows(3);
      jScrollPane3.setViewportView(fText);

      lEtat.setFont(new java.awt.Font("Dialog", 2, 12)); // NOI18N
      lEtat.setForeground(new java.awt.Color(51, 51, 51));

      lNickname.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N
      lNickname.setText("Nickname");

      tListMess.setColumns(20);
      tListMess.setRows(5);
      jScrollPane4.setViewportView(tListMess);

      lSendFile.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N
      lSendFile.setText("Send File");

      bSendFile.setText("Send");
      bSendFile.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent evt) {
            bSendFileActionPerformed(evt);
         }
      });

      bChooseFile.setText("...");
      bChooseFile.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent evt) {
            bChooseFileActionPerformed(evt);
         }
      });

      tFileName.setEditable(false);

      lFileStatus.setText("                                ");

      javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
      getContentPane().setLayout(layout);
      layout.setHorizontalGroup(
         layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
         .addGroup(layout.createSequentialGroup()
            .addGap(25, 25, 25)
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
               .addGroup(layout.createSequentialGroup()
                  .addComponent(lEtat, javax.swing.GroupLayout.PREFERRED_SIZE, 610, javax.swing.GroupLayout.PREFERRED_SIZE)
                  .addGap(0, 41, Short.MAX_VALUE))
               .addGroup(layout.createSequentialGroup()
                  .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                     .addGroup(layout.createSequentialGroup()
                        .addComponent(lUser)
                        .addGap(167, 167, 167)
                        .addComponent(lMess)
                        .addGap(0, 325, Short.MAX_VALUE))
                     .addGroup(layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                           .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 218, Short.MAX_VALUE)
                           .addComponent(lNickname)
                           .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                              .addComponent(tNickname, javax.swing.GroupLayout.Alignment.LEADING)
                              .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
                                 .addComponent(bConnect, javax.swing.GroupLayout.PREFERRED_SIZE, 85, javax.swing.GroupLayout.PREFERRED_SIZE)
                                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                 .addComponent(bDisconnect)))
                           .addGroup(layout.createSequentialGroup()
                              .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                 .addGroup(layout.createSequentialGroup()
                                    .addComponent(lSendFile)
                                    .addGap(66, 66, 66))
                                 .addGroup(layout.createSequentialGroup()
                                    .addComponent(tFileName)
                                    .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                    .addComponent(bChooseFile, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE)
                                    .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)))
                              .addComponent(bSendFile, javax.swing.GroupLayout.PREFERRED_SIZE, 65, javax.swing.GroupLayout.PREFERRED_SIZE))
                           .addComponent(lFileStatus, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                           .addGroup(layout.createSequentialGroup()
                              .addComponent(jScrollPane3, javax.swing.GroupLayout.PREFERRED_SIZE, 299, javax.swing.GroupLayout.PREFERRED_SIZE)
                              .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                              .addComponent(bSend, javax.swing.GroupLayout.PREFERRED_SIZE, 65, javax.swing.GroupLayout.PREFERRED_SIZE))
                           .addComponent(jScrollPane4))))
                  .addContainerGap())))
      );
      layout.setVerticalGroup(
         layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
         .addGroup(layout.createSequentialGroup()
            .addContainerGap()
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
               .addComponent(lUser)
               .addComponent(lMess))
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
               .addComponent(jScrollPane4, javax.swing.GroupLayout.PREFERRED_SIZE, 468, javax.swing.GroupLayout.PREFERRED_SIZE)
               .addGroup(layout.createSequentialGroup()
                  .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 383, javax.swing.GroupLayout.PREFERRED_SIZE)
                  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                  .addComponent(lSendFile)
                  .addGap(16, 16, 16)
                  .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                     .addComponent(bSendFile)
                     .addComponent(bChooseFile)
                     .addComponent(tFileName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                  .addComponent(lFileStatus, javax.swing.GroupLayout.DEFAULT_SIZE, 17, Short.MAX_VALUE)))
            .addGap(18, 18, 18)
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
               .addGroup(layout.createSequentialGroup()
                  .addComponent(lNickname)
                  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                  .addComponent(tNickname, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                  .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                  .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                     .addComponent(bDisconnect)
                     .addComponent(bConnect)))
               .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                  .addComponent(bSend, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                  .addComponent(jScrollPane3, javax.swing.GroupLayout.Alignment.TRAILING)))
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addComponent(lEtat, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE)
            .addContainerGap())
      );

      lEtat.getAccessibleContext().setAccessibleName("lEtat");

      pack();
   }// </editor-fold>//GEN-END:initComponents

    private void bSendActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bSendActionPerformed
        
        String msg = fText.getText();
        String peer = (String)listUser.getSelectedValue();
        fText.setText("");
        //msgList.addElement("> "+msg);
        tListMess.append("> ("+peer+"): "+msg+"\n");
        b.sendMessage(peer, msg);
    }//GEN-LAST:event_bSendActionPerformed

    private void bConnectActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bConnectActionPerformed
 
        b.onConnect(tNickname.getText());
        
    }//GEN-LAST:event_bConnectActionPerformed

    private void bDisconnectActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bDisconnectActionPerformed
        b.onDisconnect();

    }//GEN-LAST:event_bDisconnectActionPerformed

   private void bSendFileActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bSendFileActionPerformed
      
      if (!transfer) {
         lFileStatus.setText("Starting...");
         bSendFile.setText("Abort");
         String peer = (String)listUser.getSelectedValue();
         transfer = true;
         refreshBtns();
         b.sendFile(sendFilePath, peer, new FileTransferStatusCB() 
         {
            public void onStart() {
               lFileStatus.setText("Transfer...");
            }
            public void onFinish() {
               lFileStatus.setText("Finished !");
               transfer = false;
               bSendFile.setText("Send");
               refreshBtns();
            }
            public void onError(String msg) {
               lFileStatus.setText("Error : "+msg);
               transfer = false;
               bSendFile.setText("Send");
               refreshBtns();
            }
         });
      }
      else { // button in abort mode
         b.abortFileSend();
      }
      
   }//GEN-LAST:event_bSendFileActionPerformed

   private void bChooseFileActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bChooseFileActionPerformed
      JFileChooser fc = new JFileChooser();
      int rc = fc.showOpenDialog(this);
      if (rc == JFileChooser.APPROVE_OPTION) {
         sendFilePath = fc.getSelectedFile().getAbsolutePath();
         tFileName.setText(sendFilePath);
         refreshBtns();
      }
   }//GEN-LAST:event_bChooseFileActionPerformed

   @Override public void windowOpened(WindowEvent e) {}
   @Override public void windowClosed(WindowEvent e) {}
   @Override public void windowIconified(WindowEvent e) {}
   @Override public void windowDeiconified(WindowEvent e) {}
   @Override public void windowActivated(WindowEvent e) {}
   @Override public void windowDeactivated(WindowEvent e) {}

/* Private ********************************************************************/
   
   /** Eanble/disable buttons based on the current insatance state. */
   private void refreshBtns()
   {
      boolean peerSelected = listUser.getSelectedValue() != null;
      boolean fileSelected = sendFilePath.length() != 0;
      bChooseFile.setEnabled(!transfer);
      bSendFile.setEnabled(transfer || connected && peerSelected && fileSelected);
      bConnect.setEnabled(!connected && tNickname.getText().length() != 0);
      bDisconnect.setEnabled(connected);
      bSend.setEnabled(connected && peerSelected);
   }
   
   private JFrame _fileRecvPopup;
   
   private FromGUI b;
   private DefaultListModel userList;
   private boolean connected;
   private boolean transfer;
   private String sendFilePath;
    
   // Variables declaration - do not modify//GEN-BEGIN:variables
   private javax.swing.JButton bChooseFile;
   private javax.swing.JButton bConnect;
   private javax.swing.JButton bDisconnect;
   private javax.swing.JButton bSend;
   private javax.swing.JButton bSendFile;
   private javax.swing.JTextArea fText;
   private javax.swing.JScrollPane jScrollPane1;
   private javax.swing.JScrollPane jScrollPane3;
   private javax.swing.JScrollPane jScrollPane4;
   private java.awt.Label lEtat;
   private javax.swing.JLabel lFileStatus;
   private javax.swing.JLabel lMess;
   private javax.swing.JLabel lNickname;
   private javax.swing.JLabel lSendFile;
   private javax.swing.JLabel lUser;
   private javax.swing.JList listUser;
   private javax.swing.JTextField tFileName;
   private javax.swing.JTextArea tListMess;
   private javax.swing.JTextField tNickname;
   // End of variables declaration//GEN-END:variables
}
